#include "RdfFactory.h"
#include <iostream>
#include <string>
#include "xercesc/dom/DOM.hpp"
#include "xercesc/parsers/XercesDOMParser.hpp"
#include "xercesc/util/XMLString.hpp"
#include "xercesc/util/PlatformUtils.hpp"
#include "xercesc/framework/XMLFormatter.hpp"
#include "xercesc/sax2/SAX2XMLReader.hpp"
#include "xercesc/sax2/DefaultHandler.hpp"
#include "xercesc/sax2/ContentHandler.hpp"
#include "xercesc/sax2/Attributes.hpp"
#include "xercesc/sax2/XMLReaderFactory.hpp"
#include "xercesc/framework/StdOutFormatTarget.hpp"
#include "xercesc/framework/LocalFileFormatTarget.hpp"
#include "xercesc/framework/LocalFileInputSource.hpp"
#include "xercesc/framework/MemBufInputSource.hpp"
#include "dal/rdf/RdfSax2Handler.h"
#include "dal/rdf/RdfsSax2Handler.h"
#include "dal/rdf/RdfXmlHandler.h"
#include "dal/rdf/RdfsXmlHandler.h"
#include "XmlUtil.h"


namespace xpm {	
	using namespace xercesc;

	void RdfFactory::Init() {
		try {
			XMLPlatformUtils::Initialize();
		}catch(const XMLException& toCatch) {
			char* message = XMLString::transcode(toCatch.getMessage());
			cout << "Error during initialization!:/n" << message << endl;
			XMLString::release(&message);
		}

		XMLCh tempStr[100];
		XMLString::transcode("LS", tempStr, 99);
		m_impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
		m_domparser = ((DOMImplementationLS*)m_impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);

		XMLString::transcode("core", tempStr, 99);
		m_docImpl = DOMImplementationRegistry::getDOMImplementation(tempStr);

		m_serializer = ((DOMImplementationLS*)m_impl)->createLSSerializer();
		m_parser = new XercesDOMParser();
	

		// optionally you can set some features on this serializer
		if (m_serializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true))
			m_serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true);

		if (m_serializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true))
			m_serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);

		m_serializer->getDomConfig()->setParameter(XMLUni::fgDOMEntities, true);

		// optionally you can implement your DOMLSSerializerFilter (e.g. MyDOMLSSerializerFilter)		
	}

	RdfFactory::~RdfFactory() {
		if(m_domparser) {
			m_domparser->release();
			m_domparser = NULL;
		}
		XMLPlatformUtils::Terminate();
	}

	void RdfFactory::ParseWithDomLS(Project *project) {
		int result = true;
		/*XercesDOMParser* parser = new XercesDOMParser();
		parser->setExternalSchemaLocation(schemafile);
		parser->setValidationScheme(XercesDOMParser::Val_Always);
		parser->setDoNamespaces(true);

		ErrorHandler* errHandler = (ErrorHandler*)new HandlerBase();
		parser->setErrorHandler(errHandler);*/
		try {			
			DOMDocument *documentRdf = NULL, *documentRdfs = NULL;
			//document = m_parser->getDocument();
			documentRdf = m_domparser->parseURI((_projectSources + _rdffile).c_str());
			if(documentRdf){
				RdfXmlHandler rdfHandler(project, documentRdf, _baseName);
				rdfHandler.Parse();
				documentRdf->release();
			}
			//document = m_parser->getDocument();
			documentRdfs = m_domparser->parseURI((_projectSources + _rdfsfile).c_str());
			if(documentRdfs){
				RdfsXmlHandler rdfsHandler(project, documentRdfs, _baseName);
				rdfsHandler.Parse();
				documentRdfs->release();
			}
			
		}catch(const XMLException& toCatch) {
			char* message = XMLString::transcode(toCatch.getMessage());
			cout << "Exception message is: /n" << message << endl;
			XMLString::release(&message);
			result = false;
		}catch(const DOMException& toCatch) {
			char* message = XMLString::transcode(toCatch.getMessage());
			cout << "Exception message is: /n" << message << endl;
			XMLString::release(&message);
			result = false;
		}catch(...) {
			cout << "Unexpected Exception /n";
			result = false;
		}				
	}

	void RdfFactory::ParseWithSax2(Project *project) {
		//rdf
		SAX2XMLReader* pParserRdf = XMLReaderFactory::createXMLReader();
		RdfSax2Handler sax2HandlerRdf(project);
		pParserRdf->setContentHandler(&sax2HandlerRdf);
		//rdfs
		SAX2XMLReader* pParserRdfs = XMLReaderFactory::createXMLReader();
		RdfsSax2Handler sax2HandlerRdfs(project);
		pParserRdfs->setContentHandler(&sax2HandlerRdfs);
		try {			
			//rdf
			pParserRdf->parse((_projectSources + _rdffile).c_str());
			//rdfs
			pParserRdf->parse((_projectSources + _rdfsfile).c_str());
		}catch(const XMLException& toCatch) {
			char* message = XMLString::transcode(toCatch.getMessage());
			cout << "Exception message is: /n" << message << endl;
			XMLString::release(&message);
		}catch(const DOMException& toCatch) {
			char* message = XMLString::transcode(toCatch.getMessage());
			cout << "Exception message is: /n" << message << endl;
			XMLString::release(&message);
		}catch(...) {
			cout << "Unexpected Exception /n";
		}			
	}

	void RdfFactory::setSourceFiles(string projectSources, string rdfsFile, string rdfFile, string mynamespace) {
		_projectSources = projectSources + "\\";
		_rdfsfile = rdfsFile;
		_rdffile = rdfFile;
		size_t lastSlash = _rdffile.find_last_of(".");
		_baseName = _rdffile.substr( 0, lastSlash );
		cout << "basename :" << _baseName << endl;		
		_mynamespace = mynamespace;
	}

	void RdfFactory::save(Project *project) {
		serelizeRdf(project);
		serelizeRdfs(project);
	}

	void RdfFactory::serelizeRdf(Project* project) {
		_initialRdf = "<?xml version='1.0' encoding='UTF-8'?> \n";
		_initialRdf.append( "<!DOCTYPE rdf:RDF [ \n    <!ENTITY rdf \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"> \n");
		string rdfsEntity = "    <!ENTITY " + _baseName + " \"" + _mynamespace + _baseName + "/" + _baseName + ".rdfs#\"> \n";
		_initialRdf.append( rdfsEntity);
		string rdfEntity = "    <!ENTITY " + _baseName + "_ex \"" + _mynamespace + _baseName + "/" + _baseName + ".rdf#\"> \n";
		_initialRdf.append( rdfEntity);
		_initialRdf.append( "    <!ENTITY rdfs \"http://www.w3.org/2000/01/rdf-schema#\"> \n");
		_initialRdf.append( "    <!ENTITY xsd \"http://www.w3.org/2001/XMLSchema#\"> \n");
        _initialRdf.append( "]> \n");
		_initialRdf.append( "<rdf:RDF xmlns:rdf=\"&amp;rdf;\" xmlns:" + _baseName +"=\"&" + _baseName + ";\"  xmlns:" + _baseName + "_ex=\"&" + _baseName + "_ex;\" xmlns:xsd=\"&xsd;\" xmlns:rdfs=\"&rdfs;\"></rdf:Rdf>");
		cout << _initialRdf << endl;
		xercesc::MemBufInputSource myxml_buf((const XMLByte *)_initialRdf.c_str(), _initialRdf.size(), "dump (in memory)");
		m_parser->parse(myxml_buf);
		cout << "paserd the xml string !" << endl;
		// StdOutFormatTarget prints the resultant XML stream
		// to stdout once it receives any thing from the serializer.
		// XMLFormatTarget *myFormTarget = new StdOutFormatTarget();
		DOMLSOutput* outputRdf = ((DOMImplementationLS*)m_impl)->createLSOutput();  
		cout << "project source :" << _projectSources << endl;
		XMLFormatTarget *myRdfTarget = new LocalFileFormatTarget((_projectSources + _rdffile).c_str());
		cout << "created rdf file!" << endl;
		outputRdf->setByteStream(myRdfTarget);
		DOMDocument *documentRdf = NULL;
		/*
		Create an empty DOMDocument. When an empty document 
		is created specify the namespace of the document (optional)
		and also the root node. Both of these values can be any 
		valid text (ie. no spaces or weird characters).
		The "root node" in this example is "Hello_World". 
		(XML is case-sensitive) This root node 
		*owns everything* beneath it, just as if it were a separate object... 
		in fact, it is. It's defined by the 'DOMNode' class.

		NOTE: The namespace in this example happens to be a website
		within the 'example.com' domain [RFC2606]
		However, it does NOT have to be a domain name. 
		It could be your company name, or the name of your dog.
		It's just that domain names tend to be unique. 
		Since any name will do, there does not even have to 
		be a website at the address specified.
		*/
		// create entity in the doctype
		//create doc type
		documentRdf = m_parser->getDocument();	
		cout << "get the document from parser !" << endl;
		RdfXmlHandler rdfHandler(project, documentRdf, _baseName);
		rdfHandler.Serialize();
		m_serializer->write(documentRdf, outputRdf);
		cout << "wrote the document!" << endl;
		documentRdf->release();
		//output->release();
		delete myRdfTarget;
		cout << "serelize the document !" << endl;
	}

	void RdfFactory::serelizeRdfs(Project* project) {
		_initialRdfs = "<?xml version='1.0' encoding='UTF-8'?> \n";
		_initialRdfs.append( "<!DOCTYPE rdf:RDF [ \n    <!ENTITY rdf \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"> \n");
		_initialRdfs.append( "    <!ENTITY a 'http://protege.stanford.edu/system#'> \n");
		string rdfsEntity = "    <!ENTITY " + _baseName + " \"" + _mynamespace + _baseName + "/" + _baseName + ".rdfs#\"> \n";
		_initialRdfs.append( rdfsEntity);
		_initialRdfs.append( "    <!ENTITY rdfs \"http://www.w3.org/2000/01/rdf-schema#\"> \n");
		_initialRdfs.append( "    <!ENTITY xsd \"http://www.w3.org/2001/XMLSchema#\"> \n");
        _initialRdfs.append( "]> \n");
		_initialRdfs.append( "<rdf:RDF xmlns:rdf=\"&rdf;\" xmlns:" + _baseName +"=\"&" + _baseName + ";\" xmlns:xsd=\"&xsd;\" xmlns:rdfs=\"&rdfs;\"></rdf:Rdf>");
		cout << _initialRdfs << endl;
		xercesc::MemBufInputSource myxml_buf((const XMLByte *)_initialRdfs.c_str(), _initialRdfs.size(), "dump (in memory)");
		m_parser->parse(myxml_buf);
		// StdOutFormatTarget prints the resultant XML stream
		// to stdout once it receives any thing from the serializer.
		// XMLFormatTarget *myFormTarget = new StdOutFormatTarget();
		DOMLSOutput* outputRdfs = ((DOMImplementationLS*)m_impl)->createLSOutput();  
		XMLFormatTarget *myRdfsTarget = new LocalFileFormatTarget((_projectSources + _rdfsfile).c_str());
		//XMLFormatter formatter("UTF-8", myRdfsTarget); 
		outputRdfs->setByteStream(myRdfsTarget);
		DOMDocument *documentRdfs = NULL;
		/*
		Create an empty DOMDocument. When an empty document 
		is created specify the namespace of the document (optional)
		and also the root node. Both of these values can be any 
		valid text (ie. no spaces or weird characters).
		The "root node" in this example is "Hello_World". 
		(XML is case-sensitive) This root node 
		*owns everything* beneath it, just as if it were a separate object... 
		in fact, it is. It's defined by the 'DOMNode' class.

		NOTE: The namespace in this example happens to be a website
		within the 'example.com' domain [RFC2606]
		However, it does NOT have to be a domain name. 
		It could be your company name, or the name of your dog.
		It's just that domain names tend to be unique. 
		Since any name will do, there does not even have to 
		be a website at the address specified.
		*/
		documentRdfs = m_parser->getDocument();
		
		RdfsXmlHandler rdfsHandler(project, documentRdfs, _baseName);
		rdfsHandler.Serialize();
		m_serializer->write(documentRdfs, outputRdfs);
		documentRdfs->release();
		//output->release();
		delete myRdfsTarget;
	}

	void RdfFactory::parse(Project *project) {
		if(_isSax2)
		    ParseWithSax2(project);
		else
			ParseWithDomLS(project);
	}
}